package top.jacktgq.hsp.netty.protobuf.codec.v2;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import top.jacktgq.hsp.netty.protobuf.codec.StudentPOJO;

/**
 * @Author CandyWall
 * @Date 2020/11/12--12:42
 * @Description Netty入门：服务器端
 */
public class NettyServer {
    public static void main(String[] args) {
        EventLoopGroup bossGroup = null;
        EventLoopGroup workerGroup = null;
        try {
            //创建BossGroup和WorkerGroup
            //说明：
            //1、创建两个线程组BossGroup和WorkerGroup
            //2、BossGroup只是处理连接请求，真正和客户端的业务处理会交给WorkGroup完成
            //3、两个都是无限循环
            //4、BossGroup和WorkerGroup含有的子线程（NioEventLoop）的个数默认是 CPU核数 * 2
            bossGroup = new NioEventLoopGroup(1);
            workerGroup = new NioEventLoopGroup();
            //创建服务器端的启动对象，配置参数
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            //使用链式编程来进行设置
            serverBootstrap.group(bossGroup, workerGroup)   //设置两个线程
                    .channel(NioServerSocketChannel.class)   //使用NioSocketChannel作为服务器的通道实现
                    .option(ChannelOption.SO_BACKLOG, 128)   //设置线程队列得到的连接个数
                    .childOption(ChannelOption.SO_KEEPALIVE, true)   //设置保持活动的连接状态
                    //该Handler对应bossGroup
                    //.handler(null)
                    //改Handler对应workerGroup
                    .childHandler(new ChannelInitializer<SocketChannel>() {  //创建一个通道初始化对象
                        @Override
                        //给Pipeline设置处理器
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //将处理器类添加到Pipeline中
                            ChannelPipeline pipeline = ch.pipeline();

                            //需要加入一个ProtoBuf的解码器，才能收到客户端发来的POJO
                            //需要指定对哪种对象进行解码
                            pipeline.addLast("decoder", new ProtobufDecoder(StudentPOJO.Student.getDefaultInstance()));
                            pipeline.addLast(new NettyServerHandler());
                        }
                    });  //给我们的WorkGroup的EventLoop的对应管道设置处理器
            System.out.println("服务器准备好了");
            //绑定一个端口并且同步，生成了一个ChannelFuture对象
            //启动服务器
            ChannelFuture channelFuture = serverBootstrap.bind(6666).sync();
            System.out.println("端口绑定成功");
            //对关闭通道进行监听
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }
}
